package com.fun.demo.fun.kayang;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;


public class ADHander {

    public static String user = "ky08\\administrator";//账户
    public static String pwd = "Kayang123"; //密码 EY45Xuiq
    public static String url = "ldaps://172.18.4.19:636"; // ldaps://kypro.com:636   ldap://kypro.com:389

//    public static String user = "hey@kypro.com";//账户
//    public static String pwd = "EY45Xuiq"; //密码 EY45Xuiq
//    public static String url = "ldap://kypro.com:389"; // ldaps://kypro.com:636   ldap://kypro.com:389


    public static void main(String[] args) {
        String javaVersion = System.getProperty("java.version");
        String[] ss = javaVersion.split("_");
        int ver = Integer.parseInt(ss[1]);
        if (ver > 180) {
            System.out.println("java version:" + ver);
            //jdk1.8.181  improve ldap support
            System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
        }
        connect();
    }

    private static void connect() {
        System.out.println("url:" + url);
        System.out.println("user:" + user);
        System.out.println("pwd:" + pwd);

//        String cert = "C:/Program Files/Java/jdk1.8.0_202/jre/lib/security/cacerts";
//        System.setProperty("javax.net.ssl.trustStore", cert);

        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.PROVIDER_URL, url);
        env.put(Context.SECURITY_PRINCIPAL, user);
        env.put(Context.SECURITY_CREDENTIALS, pwd);
        env.put(Context.SECURITY_AUTHENTICATION, "simple"); //"none"、"simple" 和 "strong"
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
//      env.put(Context.AUTHORITATIVE, "true");

        if (url.toLowerCase().startsWith("ldaps:")) {
            env.put("java.naming.ldap.factory.socket", CustomSSLSocketFactory.class.getName());
            System.out.println("AD : SSL PROTOCOL");
//            env.put(Context.SECURITY_PROTOCOL, "ssl");
        }
        LdapContext ctx = null;
        try {
            ctx = new InitialLdapContext(env, null);


            System.out.println("InitialDirContext OK.");

            ctx.reconnect(null);
            System.out.println("reconnect OK");

            //获取某个组织
//            String ouPath22 =  "OU=笔记本,OU=实施部,OU=Kayang,DC=kypro,DC=com" ;
//            seachADOU2(ouPath22, ctx);

            //获取用户列表
//              String ouPath2 = "CN=HeY何毅,OU=研发部,OU=Kayang,DC=kypro,DC=com";//某个用户
//              String ouPath2 = "OU=行政部,OU=Kayang,DC=kypro,DC=com"; //某个部门

            String name = "Amos测试" + LocalDateTime.now().getSecond();
            String ouPath2 = "CN=" + name + ",OU=研发组,OU=研发中心,OU=Kayang,DC=ky08,DC=com"; //所有
            //createUser(ctx, ouPath2);

            //        ouPath2 = "OU=Kayang,DC=ky08,DC=com"; //所有
            //        ouPath2 = "OU=研发部,OU=Kayang,DC=kypro,DC=com"; //所有
            ouPath2 = "CN=Amos测试32,OU=研发组,OU=研发中心,OU=kayang,DC=ky08,DC=com";
            String filter = "";
       //     seachADUser(ouPath2, ctx, filter);

            Attributes attrs = new BasicAttributes();
//userAccountControl
            //pwdLastSet
            //accountExpires

            // 512 on   514 off  546
            attrs.put("userAccountControl", "512");
//


            //accountExpires: 133360704000000000 2023-8.9

            //accountExpires: 133361568000000000,  2023-8-10


            // 86400 * 1000 * 10000
            System.out.println(133361568000000000L / 864000000000L); //154353  422Y

            Calendar calendar = Calendar.getInstance();
            calendar.clear();
            calendar.set(1601, 0, 1, 0, 0);

            long t1601 = calendar.getTime().getTime();
            System.out.println("t1601:" + t1601);

            long tnow = LocalDateTime.now().plusDays(6).toInstant(ZoneOffset.of("+8")).toEpochMilli();

         //   attrs.put("AccountExpires", (tnow -t1601) * 10000 + "");

            System.out.println("ok:" + (tnow -t1601) * 10000 + "");

  //            modifyAttrs(ctx, attrs, ouPath2); 修改具体属性

            //修改某个用户密码
//            String userDN = "CN=HeY何毅,OU=研发部,OU=Kayang,DC=kypro,DC=com";
//            String newPwd = "QWEqwe123";
            // AD域密码策略不确定性
            // modifyPassword(ctx, newPwd, userDN);
            //  modifyPassword2(ctx, newPwd, userDN);

        } catch (AuthenticationException e) {
            e.printStackTrace();
        } catch (javax.naming.CommunicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != ctx) {
                try {
                    ctx.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }


    public static void createUser(DirContext ctx, String path) {

        Attributes attrs = new BasicAttributes();
        Attribute objclassSet = new BasicAttribute("objectClass");
        objclassSet.add("top");
        objclassSet.add("user");
        attrs.put(objclassSet);
        String name = "AmosTest" + LocalDateTime.now().getSecond();
        attrs.put("sAMAccountName", name);

        attrs.put("C", "CN"); // 中国：CN    台湾：TW
        attrs.put("St", "上海市");
        attrs.put("L", "上海市");


        // attrs.put("aabbcc", "自定义属性");

        try {
            ctx.createSubcontext(path, attrs);
            System.out.println("创建用户" + name + "成功");
        } catch (NamingException e) {
            e.printStackTrace();
        }

    }


    public static void modifyAttrs(DirContext ctx, Attributes attrs, String userDN) {
        try {
            ctx.modifyAttributes(userDN, DirContext.REPLACE_ATTRIBUTE, attrs);
            System.out.println("modify ok");
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }


    public static void modifyPassword(DirContext ctx, String newPwd, String userDN) {
        // String account = "HeY";
        ModificationItem[] modificationItems = new ModificationItem[2];
        modificationItems[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("unicodePwd", getPassword(newPwd)));
        // modificationItems[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("pwdLastSet", "0"));
        try {
            ctx.modifyAttributes(userDN, modificationItems);
            System.out.println("密码修改成功，新密码 ：" + newPwd);
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }


    public static void modifyPassword2(DirContext ctx, String newPwd, String userDN) {
        ModificationItem[] mods = new ModificationItem[1];
        mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", getPassword(newPwd)));

        // 修改密码
        try {
            ctx.modifyAttributes(userDN, mods);
        } catch (NamingException e) {
            e.printStackTrace();
        }

    }

    public static void seachADOU2(String ouPath, DirContext ctx) throws NamingException {
        String searchBase = ouPath;
        String searchFilter = "(&(objectCategory=organizationalUnit))";
        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE);
        NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
        int rows = 0;
        while (answer.hasMoreElements()) {
            SearchResult sr = (SearchResult) answer.next();
            System.out.println((rows + 1) + " ************************************************");
            String dn = sr.getName();
            System.out.println("dn:" + dn);

            Attributes Attrs = sr.getAttributes();
            if (Attrs != null) {
                System.out.println(Attrs.toString());
                try {
                    for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore(); ) {
                        Attribute Attr = (Attribute) ne.next();
                        System.out.println("AttributeID:" + Attr.getID());
                        int k = 0;
                        for (NamingEnumeration e = Attr.getAll(); e.hasMore(); k++) {
                            String val = e.next().toString();
                            System.out.println("AttributeValues:" + val);
                        }
                    }
                } catch (NamingException e) {
                    System.err.println("Throw Exception:" + e);
                }
            }
            rows++;
        }
    }

    public static void seachADOU(String ouPath, DirContext ctx) throws NamingException {
        String searchBase = ouPath;
        String searchFilter = "(&(objectCategory=organizationalUnit)(objectClass=top))";
        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
        int rows = 0;
        while (answer.hasMoreElements()) {
            SearchResult sr = (SearchResult) answer.next();
            System.out.println((rows + 1) + " ************************************************");
            String dn = sr.getName();
            System.out.println("dn:" + dn);

            Attributes Attrs = sr.getAttributes();
            if (Attrs != null) {
                System.out.println(Attrs.toString());
                try {
                    for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore(); ) {
                        Attribute Attr = (Attribute) ne.next();
                        System.out.println("AttributeID:" + Attr.getID());
                        int k = 0;
                        for (NamingEnumeration e = Attr.getAll(); e.hasMore(); k++) {
                            String val = e.next().toString();
                            System.out.println("AttributeValues:" + val);
                        }
                    }
                } catch (NamingException e) {
                    System.err.println("Throw Exception:" + e);
                }
            }
            rows++;
        }
    }

    public static void seachADUser(String ouPath, DirContext ctx, String custonFilter) throws NamingException {
        String searchBase = ouPath;
        String searchFilter = String.format("(&(objectCategory=person)(objectClass=user)%s)", custonFilter);
        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        String returnedAtts[] = {"*"}; // 搜索哪些属性
        searchCtls.setReturningAttributes(returnedAtts);
        NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);
        int rows = 0;
        while (answer.hasMoreElements()) {
            if (rows == 10) {
//                break;
            }
            SearchResult sr = (SearchResult) answer.next();
            System.out.println((rows + 1) + " ************************************************");
            String dn = sr.getName();
            System.out.println("dn:" + dn);

            Attributes attrs = sr.getAttributes();
            if (attrs != null) {
                //    System.out.println(attrs.toString());
                try {
                    for (NamingEnumeration ne = attrs.getAll(); ne.hasMore(); ) {
                        Attribute attr = (Attribute) ne.next();
                        String attrId = attr.getID();
                        StringBuilder sb = new StringBuilder();
                        for (NamingEnumeration e = attr.getAll(); e.hasMore(); rows++) {
                            String val = e.next().toString();
                            sb.append(val);
                            sb.append(", ");
                        }
                        System.out.println(attrId + ": " + sb.toString());
                    }
                } catch (NamingException e) {
                    System.err.println("Throw Exception:" + e);
                }
            }

        }
    }

    /**
     * 获取格式化的密码
     */
    public static byte[] getPassword(String newPass) {
        String quotedPassword = "\"" + newPass + "\"";
        //return quotedPassword.getBytes("UTF-16LE");
        char unicodePwd[] = quotedPassword.toCharArray();
        byte pwdArray[] = new byte[unicodePwd.length * 2];
        for (int i = 0; i < unicodePwd.length; i++) {
            pwdArray[i * 2 + 1] = (byte) (unicodePwd[i] >>> 8);
            pwdArray[i * 2 + 0] = (byte) (unicodePwd[i] & 0xff);
        }
        return pwdArray;
    }


    // 绕过SSL证书校验
    public static class CustomSSLSocketFactory extends SSLSocketFactory {
        private SSLSocketFactory socketFactory;

        public CustomSSLSocketFactory() {
            try {
                SSLContext ctx = SSLContext.getInstance("TLS");
                ctx.init(null, new TrustManager[]{new DummyTrustmanager()}, new SecureRandom());
                socketFactory = ctx.getSocketFactory();
            } catch (Exception ex) {
                ex.printStackTrace(System.err);
            }
        }

        public static SocketFactory getDefault() {
            return new CustomSSLSocketFactory();
        }

        @Override
        public String[] getDefaultCipherSuites() {
            return socketFactory.getDefaultCipherSuites();
        }

        @Override
        public String[] getSupportedCipherSuites() {
            return socketFactory.getSupportedCipherSuites();
        }

        @Override
        public Socket createSocket(Socket socket, String string, int num, boolean bool) throws IOException {
            return socketFactory.createSocket(socket, string, num, bool);
        }

        @Override
        public Socket createSocket(String string, int num) throws IOException, UnknownHostException {
            return socketFactory.createSocket(string, num);
        }

        @Override
        public Socket createSocket(String string, int num, InetAddress netAdd, int i) throws IOException, UnknownHostException {
            return socketFactory.createSocket(string, num, netAdd, i);
        }

        @Override
        public Socket createSocket(InetAddress netAdd, int num) throws IOException {
            return socketFactory.createSocket(netAdd, num);
        }

        @Override
        public Socket createSocket(InetAddress netAdd1, int num, InetAddress netAdd2, int i) throws IOException {
            return socketFactory.createSocket(netAdd1, num, netAdd2, i);
        }


        /**
         * 证书
         */
        public static class DummyTrustmanager implements X509TrustManager {
            public void checkClientTrusted(X509Certificate[] cert, String string) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] cert, String string) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }

        }
    }


}

